/**
 * https://www.bilibili.com/video/BV1Mb411e7re?p=23
 * DS1302 实时时钟(时钟芯片) & 可调时钟
 *  DS1302是由美国DALLAS公司推出的具有涓细电流充电能力的低功耗实时时钟芯片。
 *      它可以对年、月、日、周、时、分、秒进行计时，且具有闰年补偿等多种功能
 *      RTC(Real Time Clock)：实时时钟，是一种集成电路，通常称为时钟芯片
 * 共8个引脚:
 *  GND:  接地
 *  Vcc1: 备用电池,可充电类型 (需自己外接)
 *  Vcc2: 主电源
 *  X1,X2: 接32.768KHz晶振 (需自己外接)
 *  CE:    使能, 高电平有效
 *  IO:    数据输入/输出
 *  SCLK:  串行时钟 (上升沿读写)
 * 
 * DS12C887
 *      内部有电池, 掉电可继续计时:
 *          https://www.bilibili.com/video/BV1dD4y1X7Vo/?vd_source=eec92494e7d9882d1d896c25dff0578a
 *          TX-1C的时钟芯片需要连线: 0:56:58
 * 
 * https://www.bilibili.com/video/BV1Mb411e7re?p=24
 */
#include <REGX52.H>
#include "Link/Single_Keyboard_Utils.h"
#include "Link/Timer0_Utils.h"
#include "Link/LCD1602_Utils.h"
#include "Link/DS1302_Utils.h"

void TimeShow();
void TimeSet();
static void Timer0_Rountine();

//索引0~6分别为年、月、日、时、分、秒、星期(10进制)
unsigned char DS1302_Times[7] = {23, 2, 17, 12, 11, 37, 6};
/**
 * isEditMODE: 独立按键1: 切换显示模式/修改时间模式
 */
static unsigned char key = 0, isEditMODE = 0, TimeSetSelect = 0, TimeFlashFlag = 0;
void main_DS1302() {
    LCD1602_Init(1);
    //静态字符初始化显示, Real Time Clock
    LCD_ShowString(1, 1, "  -  -       RTC");
    LCD_ShowString(2, 1, "  :  :  ");
    //定时器0, 10ms溢出1次
    Timer0_Init(10000, 0);
    Timer0_setOnTickListener_Exact(1, &Timer0_Rountine);

    //关闭写保护
    DS1302_Write_Able(1);
    //写数据, 年、月、日、时、分、秒、星期(10进制)
    // DS1302_Times = {23, 2, 17, 12, 11, 37, 6};
    //1.写时间
    DS1302_SetTime(DS1302_Times);
    //2.读取 & 显示时间
    TimeShow();
    //3.监听按键, 调整时钟
    while (1) {
        key = Single_Keyboard_Down_Delay(1);
        switch (key) {
        case 1://是否可编辑
            isEditMODE = ~isEditMODE;
            if (isEditMODE) {
                TimeSetSelect = 0;  //功能切换
                TimeSet();
            } else {
                DS1302_SetTime(DS1302_Times);
                TimeShow();
            }
            break;
        default:
            break;
        }
    }

    //打开写保护
    DS1302_Write_Able(0);
    // while (1);
}

//2.读取 & 显示时间
void TimeShow(void) {
    //读取, 返回10进制
	DS1302_ReadTime(DS1302_Times);
    //显示时间
    LCD_ShowNum(1, 1, DS1302_Times[0], 2);  //年
    LCD_ShowNum(1, 4, DS1302_Times[1], 2);  //月
    LCD_ShowNum(1, 7, DS1302_Times[2], 2);  //日
    LCD_ShowNum(2, 1, DS1302_Times[3], 2);  //时
    LCD_ShowNum(2, 4, DS1302_Times[4], 2);  //分
    LCD_ShowNum(2, 5, DS1302_Times[5], 2);  //秒
}

/**
 * 2.可调时钟
 */
void TimeSet() {
    switch (key) {
    case 2:                 //向右选择修改的光标位置
        TimeSetSelect ++;   //设置选择位加1
		TimeSetSelect %= 6; //越界清零
        break;
    case 3:                 //时间设置位数值 +1
        DS1302_Times[TimeSetSelect] ++;
        //判断时间正确性
		judgeDateTime(DS1302_Times);
        break;
    case 4:                 //时间设置位数值 -1
        DS1302_Times[TimeSetSelect] --;
        //判断时间正确性
		judgeDateTime(DS1302_Times);
        break;
    default:
        break;
    }
    //更新显示，根据 TimeSetSelect 和 TimeFlashFlag 判断可完成闪烁功能
    switch (TimeSetSelect) {
    case 0: if (TimeFlashFlag) LCD_ShowString(1, 1, "  "); else LCD_ShowNum(1, 1, DS1302_Times[0], 2); break;
    case 1: if (TimeFlashFlag) LCD_ShowString(1, 4, "  "); else LCD_ShowNum(1, 4, DS1302_Times[1], 2); break;
    case 2: if (TimeFlashFlag) LCD_ShowString(1, 7, "  "); else LCD_ShowNum(1, 7, DS1302_Times[2], 2); break;
    case 3: if (TimeFlashFlag) LCD_ShowString(2, 1, "  "); else LCD_ShowNum(2, 1, DS1302_Times[3], 2); break;
    case 4: if (TimeFlashFlag) LCD_ShowString(2, 4, "  "); else LCD_ShowNum(2, 4, DS1302_Times[4], 2); break;
    case 5: if (TimeFlashFlag) LCD_ShowString(2, 7, "  "); else LCD_ShowNum(2, 7, DS1302_Times[5], 2); break;
    default:
        break;
    }
}

static void Timer0_Rountine() {
    static unsigned char T0Count = 0;
    T0Count ++;
    if (T0Count >= 50) {   //每500ms进入一次
        T0Count=0;
        //闪烁标志位取反
        TimeFlashFlag = !TimeFlashFlag;
    }
}